import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;

import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;


public class NetworkBlast extends ClusteringAlgorithms{

	// This is the output of network blast.
	private String CLUSTERS_FILE = "out-network.prop";
	private int NOT_INIT = -1;

	public NetworkBlast() {
		super("in0_int");
	}

	public LinkedList<Cluster> getClusters(
			SimpleWeightedGraph<String, DefaultWeightedEdge> net,
			HashMap<String, Gene> geneMap) {
		writeNetworkFile(net);
		runNetworkBlastCommand();
		LinkedList<Cluster> clusters = readClustersFile(geneMap);
		return clusters;
	}
	

	private void runNetworkBlastCommand() {
		Runtime run = Runtime.getRuntime();
		Process runNetworkBlast;
		// This is the command to run networkblast.
//		String[] command ={ Consts.NETWORKBLAST_DIR+"networkblast","-i" ,Consts.CUR_DIR+"input","-o",Consts.CUR_DIR+"out"};
		String[] command ={ Consts.NETWORKBLAST_DIR+"networkblast","-i" , Consts.DATA_DIR + "in","-o", "out"}; // Oded version
		try {
			runNetworkBlast = run.exec(command);
			runNetworkBlast.waitFor();
		} catch (InterruptedException ine) {
			System.err.println("Running NetworkBlast is interrupted by another thread");
		} catch (IOException ioe) {
			System.err.println("Can't execute NetworkBlast since:");
			System.err.println(ioe.getMessage());
			System.exit(1);
		}
	}

	private LinkedList<Cluster> readClustersFile(HashMap<String, Gene> geneMap) {
		
		// This hash maps from ID to cluster.
		// It will be used later on to extract the clusters
		// from the output of network_blast.
		HashMap<Integer,Cluster> mapIDToCluster = new HashMap<Integer, Cluster>();
		BufferedReader read;
		String line;
		int spaceInd;
		String prot;
		int firstBracketsInd;
		int secBracketsInd;
		String protClusterStr;
		try {
			// read = new BufferedReader(new FileReader(Consts.CUR_DIR+CLUSTERS_FILE)); // TEMP TODO Liat version.
			 read = new BufferedReader(new FileReader(CLUSTERS_FILE));
			// skip the first line.
			read.readLine();
			while (((line = read.readLine()) != null) ) {
				spaceInd = line.indexOf(" ");
				firstBracketsInd = line.indexOf("(");
				secBracketsInd = line.indexOf(")");
				if ((spaceInd != NOT_INIT) && (firstBracketsInd != NOT_INIT) && (secBracketsInd != NOT_INIT)) {
					prot = line.substring(0,spaceInd);
					protClusterStr  = line.substring(firstBracketsInd+1,secBracketsInd);
					//System.out.println("protein:"+prot+" protStr:"+protClusterStr);
					parseProtCluster(prot,protClusterStr,mapIDToCluster, geneMap);
				}
			}
			read.close();
		} catch (IOException ioe) {
			System.err.println("Can't read the clusters file since: ");
			System.err.println(ioe.getMessage());
			System.exit(1);
		}
		Collection<Cluster> clustersSet = mapIDToCluster.values();
		LinkedList<Cluster> clusters = new LinkedList<Cluster>(clustersSet);
		return clusters;
	}

	
	private void parseProtCluster(String prot,String protClusterStr, HashMap<Integer,Cluster>mapIDToCluster,
			HashMap<String, Gene> geneMap) {
		Gene gene = geneMap.get(prot);
		assert(gene != null);
		
		String[] protClusters = protClusterStr.split("::");
		String clusterIDStr;
		int clusterID = -1;
		Cluster cluster;
		for(int i=0; i < protClusters.length; i++) {
			clusterIDStr = protClusters[i];
			clusterID = Integer.valueOf(clusterIDStr);
			if (! mapIDToCluster.containsKey(clusterID)) {
				cluster = new Cluster();
				mapIDToCluster.put(clusterID, cluster);				

			} else {// This is not new cluster
				cluster = mapIDToCluster.get(clusterID);
				//if (clusterID == 4) {
				//	System.out.println(mapIDToCluster.get(clusterID));
				//}
			}
			cluster.add(gene);
			//System.out.println("index:"+clusterID+" cluster:"+cluster.toString());
		}
	}
	
	public static void main(String[] args) {
		// Tester for NETWORK BLAST
		// MapToAnnot.init(); // TEMP TODO consider remove
		// BuildNet build = new BuildNet(); // TEMP TODO consider remove
		// Network net = build.generateNet("102.sif");
		String netFileName = args[0];

		HashMap<String, Gene> geneMap = new HashMap<String, Gene>();
		SimpleWeightedGraph<String, DefaultWeightedEdge> net = 
			PPIFactory.generate(geneMap, netFileName);

		NetworkBlast blastNet = new NetworkBlast();
		LinkedList<Cluster> clusters = blastNet.getClusters(net, geneMap);
		for (Cluster clus: clusters) {
			System.out.println(clus);
		}
	}
}
